using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Microsoft.SqlServer.Dts.Runtime;

namespace Microsoft.SharedSource.SqlServer.MDDE.Components
{
    [
        System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1705:LongAcronymsShouldBePascalCased"),
        SupportedComponentType("Microsoft.SqlServer.Dts.Runtime.ConnectionManager")
    ]
    public sealed class MDDEConnectionManager:MDDEComponent
    {
        #region Member Variables

        private ConnectionManager component = null;
        private XmlNodeList changedProperties = null;

        #endregion

        public ConnectionManager InnerConnectionManager
        {
            get
            {
                return (ConnectionManager)innerComponent;
            }
        }

        public MDDEConnectionManager(Package package, Object component, string name, string uri)
            : base(package, component, name, uri)
        {
        }

        #region Overridden Members

        public override void GetChangeXml(MDDEComponent subject, XmlDocument changeXml)
        {
            #region Set Values

            if (subject == null)
                throw new ArgumentNullException("Subject can not NULL");

            if (!(subject is MDDEConnectionManager))
                throw new ArgumentException("Subject is not of type MDDEConnectionManager");

            component = (ConnectionManager)innerComponent;
            ConnectionManager referenceComponent = (ConnectionManager)subject.InnerComponent;

            DtsProperties componentPropertyCollection = (DtsProperties)component.Properties;
            DtsProperties referenceComponentPropertyCollection = (DtsProperties)referenceComponent.Properties;

            XmlNode connectionManagerNode = null;
            connectionManagerNode = changeXml.CreateElement("ConnectionManager");

            bool nodeEmpty = true;

            #endregion

            #region Compare properties of Connection Manager with subject and create Properties' Xml

            for (int propertyIndex = 0; propertyIndex < componentPropertyCollection.Count; propertyIndex++)
            {
                if (componentPropertyCollection[propertyIndex].Name.CompareTo("Name") == 0)
                    continue;

                DtsProperty componentProperty = componentPropertyCollection[propertyIndex];
                DtsProperty referenceComponentProperty = referenceComponentPropertyCollection[propertyIndex];

                if ((componentProperty.Get && componentProperty.Set)
                    && (referenceComponentProperty.Get && referenceComponentProperty.Set))
                {
                    string componentPropertyValue = String.Empty;
                    if (componentProperty.GetValue(component) != null)
                        componentPropertyValue = componentProperty.GetValue(component).ToString();

                    string referenceComponentPropertyValue = String.Empty;
                    if (referenceComponentProperty.GetValue(referenceComponent) != null)
                        referenceComponentPropertyValue = referenceComponentProperty.GetValue(referenceComponent).ToString();

                    if (componentPropertyValue != referenceComponentPropertyValue)
                    {
                        UpdateNodeProperties(changeXml, connectionManagerNode, componentProperty.Name, componentPropertyValue);
                        nodeEmpty = false;
                    }
                }
            }

            #endregion

            #region Update Changes Xml

            if (!nodeEmpty)
            {
                AddAttribute(changeXml, connectionManagerNode, "Name", this.name);
                AddAttribute(changeXml, connectionManagerNode, "URL", this.uri);

                changeXml.FirstChild.AppendChild(connectionManagerNode);
            }

            #endregion
        }

        public override bool ApplyChanges(XmlDocument changeXml, MDDEExecutionDAG originalPackage)
        {
            try
            {
                #region Set Values

                XmlNode componentChangeXml =
                    changeXml.SelectSingleNode("//PackageChanges/ConnectionManager[@URL='" + this.uri + "']");

                if (componentChangeXml == null)
                    return true;

                //if (innerComponent == null)
                //    return false;

                //if (!(innerComponent is ConnectionManager))
                //    return false;

                component = (ConnectionManager)innerComponent;

                #endregion

                #region Read Change Xml

                if (componentChangeXml.SelectSingleNode("Properties") != null)
                    changedProperties = componentChangeXml["Properties"].ChildNodes;

                if (changedProperties == null)
                    return true;

                #endregion

                #region Apply Properties

                if (!this.package.Connections.Contains(this.name))
                    return false;

                DtsProperties dtsProperties = this.package.Connections[this.name].Properties;

                foreach (XmlNode changedProperty in changedProperties)
                {
                    dtsProperties[changedProperty.Attributes["Name"].Value].SetValue(this.package.Connections[this.name],
                            changedProperty.Attributes["Value"].Value);
                }

                #endregion

                return true;
            }
            
            catch
            {
                // TODO: Add to Log
                return false;
            }
        }

        public override XmlDocument GetComponentTree()
        {
            XmlDocument xConnectionManager = new XmlDocument();

            // Create the 'Node' node.
            XmlElement xRoot =
                AppendChildElement(
                xConnectionManager,
                "Node",
                new string[]{
                    "Type", "ConnectionManager",
                    "Name", InnerConnectionManager.Name,
                    "Uri", Uri,
                    "ClassId", "Microsoft.SqlServer.Dts.Runtime.ConnectionManager",
                    "RowsetDescriptorType", string.Empty,
                    "ContainsMappings", "False",
                    "ContainsCollections", "False"
                });

            // Append the properties.
            base.AppendDtsProperties(
                xRoot, (IDTSPropertiesProvider)InnerConnectionManager);

            return xConnectionManager;
        }

        public override bool Validate()
        {
            return true;
        }

        #endregion

        #region Helper Methods

        private void UpdateNodeProperties(XmlDocument xmlDoc, XmlNode parentNode, string name, string value)
        {
            if (parentNode.ChildNodes.Count == 0)
                AddChildNode(xmlDoc, parentNode, "Properties");

            XmlNode propertiesNode = parentNode.ChildNodes[0];

            XmlNode propertyNode = AddChildNode(xmlDoc, propertiesNode, "Property");
            AddAttribute(xmlDoc, propertyNode, "Name", name);
            AddAttribute(xmlDoc, propertyNode, "Value", value);
        }

        private XmlNode AddChildNode(XmlDocument xmlDoc, XmlNode parentNode, string name)
        {
            parentNode.AppendChild(xmlDoc.CreateNode(XmlNodeType.Element, name, null));
            return parentNode.LastChild;
        }

        private void AddAttribute(XmlDocument xmlDoc, XmlNode parentNode, string name, string value)
        {
            XmlNode xmlAttrib = xmlDoc.CreateAttribute(name);
            xmlAttrib.InnerText = value;
            parentNode.Attributes.Append((XmlAttribute)xmlAttrib);
        }

        #endregion
    }
}
